//
// Created by mabinjie on 2024/10/23.
//

#ifndef JTT808_HEADER_HPP
#define JTT808_HEADER_HPP
#include <cstdint>
#include <ostream>
#include <common/base.hpp>
#include <common/macros.hpp>
#include <utility>

#include "jtt808_body.hpp"
#include "common/types.h"

namespace protocol {
    struct segmentation final : common::Sizeable, common::ToString, common::Serializable {
        uint16_t packet_total{};
        uint16_t packet_index{};

        segmentation() = default;

        segmentation(const uint16_t packet_total, const uint16_t packet_index)
            : packet_total(packet_total),
              packet_index(packet_index) {
        }

        IMPLEMENT_SIZEABLE(packet_total, packet_index)
        IMPLEMENT_TOSTRING(packet_total, packet_index)

        void serialize(common::MessagePackWriter &writer) override {
            writer.writeUint(packet_total);
            writer.writeUint(packet_index);
        }

        void deserialize(common::MessagePackReader &reader) override {
            reader.readUint(packet_total);
            reader.readUint(packet_index);
        }
    };

struct MessageAttribute final : common::Sizeable, common::ToString, common::Serializable {
    bool remained{false};
    bool has_version{true};
    bool is_segment{false};
    bool is_encrypted{false};
    uint16_t message_length{0};

    MessageAttribute() = default;
    MessageAttribute(const bool is_segment, const bool is_encrypted, const uint16_t message_length)
        : is_segment(is_segment), is_encrypted(is_encrypted), message_length(message_length&0x3FF) {}

    void serialize(common::MessagePackWriter &writer) override {
        std::bitset<16> bits;
        bits.set(15, remained);
        bits.set(14, has_version);
        bits.set(13, is_segment);
        if (is_encrypted) bits.set(10, true);
        const auto result = bits | std::bitset<16>(message_length);
        const uint16_t to = result.to_ulong();
        writer.writeUint(to);
    }

    void deserialize(common::MessagePackReader &reader) override {
        uint16_t read;
        reader.readUint(read);
        const std::bitset<16> bits(read);
        has_version = bits[14];
        is_segment = bits[13];
        is_encrypted = bits[12];
        message_length = (std::bitset<16>(0x3ff) & bits).to_ulong();
    }

    [[nodiscard]] std::string toString() const override {
        std::stringstream ss;
        ss << "MessageAttribute(is_segment:" << is_segment << ", is_encrypted:" << is_encrypted << ", message_length:"
                << static_cast<int>(message_length) << ") ";
        return ss.str();
    }

protected:
    [[nodiscard]] size_t size() const override {
        return sizeof(uint16_t);
    }
};


class jtt808_header final : public common::Serializable, public common::Sizeable, public common::ToString {
public:
    uint16_t message_id_{};
    MessageAttribute attribute_{};
    uint8_t version_{};
    common::Bcd<20> phone_number_;
    uint16_t message_sn_{};
    segmentation segmentation_;

    IMPLEMENT_SIZEABLE(message_id_, attribute_, version_, phone_number_, message_sn_, segmentation_)
    IMPLEMENT_TOSTRING(message_id_, attribute_, version_, phone_number_, message_sn_, segmentation_)

    jtt808_header() = default;

    jtt808_header(const jtt808_body_ptr& body, const MessageAttribute& attribute, const uint8_t version,
                  const std::string &number, const uint16_t message_sn,
                  segmentation segmentation)
        : message_id_(body->message_id_),
          attribute_(attribute),
          version_(version),
          phone_number_(number),
          message_sn_(message_sn),
          segmentation_(std::move(segmentation)) { }

    jtt808_header(const jtt808_header& other)
        : message_id_(other.message_id_), attribute_(other.attribute_), version_(other.version_),
          phone_number_(other.phone_number_), message_sn_(other.message_sn_), segmentation_(other.segmentation_) {}

    void serialize(common::MessagePackWriter &writer) override {
        writer.writeUint(message_id_);
        attribute_.serialize(writer);
        writer.writeUint(version_);
        phone_number_.serialize(writer);
        writer.writeUint(message_sn_);
        segmentation_.serialize(writer);
    }

    void deserialize(common::MessagePackReader &reader) override {
        reader.readUint(message_id_);
        attribute_.deserialize(reader);
        reader.readUint(version_);
        phone_number_.deserialize(reader);
        reader.readUint(message_sn_);
        segmentation_.deserialize(reader);
    }
};

}

#endif //JTT808_HEADER_HPP
